package ru.osu.acm.testing.beans;

import ru.osu.acm.common.config.Config;
import ru.osu.acm.common.industrial.TestcaseFactory;
import ru.osu.acm.common.industrial.ProblemFactory;
import ru.osu.acm.common.entities.Problem;
import ru.osu.acm.common.entities.Testcase;
import ru.osu.acm.testing.Utils;
import ru.osu.acm.system.ProcessStreamReader;

import javax.annotation.Resource;
import javax.sql.DataSource;
import javax.faces.context.FacesContext;
import javax.faces.application.FacesMessage;
import java.util.ArrayList;
import java.io.*;

import org.apache.myfaces.custom.fileupload.UploadedFile;

/**
 * User: aleksey
 * Date: Sep 28, 2009
 * Time: 2:14:47 PM
 */
public class TestcaseBean {
    @Resource(name = Config.jndi)
    private DataSource source;

    private Problem problem = null;

    public Problem getProblem() {
        return problem;
    }

    private Testcase viewingTest = null;

    public Testcase getViewingTest() {
        return viewingTest;
    }

    private Testcase editingTest = null;

    public Testcase getEditingTest() {
        return editingTest;
    }

    private UploadedFile uploadedFile = null;

    public UploadedFile getUploadedFile() {
        return uploadedFile;
    }

    public void setUploadedFile(UploadedFile uploadedFile) {
        this.uploadedFile = uploadedFile;
    }

    public ArrayList<Testcase> getTests() {
        return TestcaseFactory.getTestsForProblem(problem.getId(), Utils.getConnection(source), true);
    }

    // Action handlers

    public String viewTests() {
        problem = ProblemFactory.getProblem(Integer.parseInt(Utils.getRequestParam("problem")), Utils.getConnection(source), true);
        return "list_of_tests";
    }

    public String viewTest() {
        viewingTest = TestcaseFactory.getTestcase(Integer.parseInt(Utils.getRequestParam("testcase")), Utils.getConnection(source), true);
        return "test_viewer";
    }

    public String editTest() {
        editingTest = TestcaseFactory.getTestcase(Integer.parseInt(Utils.getRequestParam("testcase")), Utils.getConnection(source), true);
        return "test_editor";
    }

    public String deleteTest() {
        int testId = Integer.parseInt(Utils.getRequestParam("testcase"));
        TestcaseFactory.deleteTestcase(testId, problem.getId(), Utils.getConnection(source), true);
        return null;
    }

    public String createTest() {
        editingTest = TestcaseFactory.getNewTestcase();
        editingTest.setProblem(problem);
        editingTest.setIndex(TestcaseFactory.getTestCountForProblem(problem.getId(), Utils.getConnection(source), true));
        return "test_editor";
    }

    public String deleteAllTests() {
        TestcaseFactory.deleteAllTests(problem.getId(), Utils.getConnection(source), true);
        return null;
    }

    public String saveTest() {
        TestcaseFactory.updateTestcase(editingTest, Utils.getConnection(source), true);
        editingTest = TestcaseFactory.getTestcase(editingTest.getId(), Utils.getConnection(source), true);
        return null;
    }

    public String upload() {
        String uploadedFileName = uploadedFile.getName();

        String fullFileDir = System.getProperty("java.io.tmpdir") + File.separatorChar + "olgaweb";
        String fullFilePath = fullFileDir + File.separatorChar + uploadedFileName;

        File uploadDir = new File(fullFileDir);
        uploadDir.mkdirs();
        Utils.clearDir(uploadDir);

        File localFile = new File(fullFilePath);
        try {
            InputStream inputStream = uploadedFile.getInputStream();
            FileOutputStream fileOutputStream = new FileOutputStream(localFile);
            byte[] buf = new byte[1024];
            int i;
            while ((i = inputStream.read(buf)) != -1) {
                fileOutputStream.write(buf, 0, i);
            }
            inputStream.close();
            fileOutputStream.close();
        }
        catch (IOException e) {
            FacesContext.getCurrentInstance().addMessage("upload_7z", new FacesMessage(FacesMessage.SEVERITY_ERROR, "Error uploading file", null));
            e.printStackTrace();
        }

        String extractString = Config.archiverExtractString;
        extractString = extractString.replace("%FULLFILEPATH%", fullFilePath);
        extractString = extractString.replace("%FULLFILEDIR%", fullFileDir);
        try {
            Process p = Runtime.getRuntime().exec(extractString, null, new File(fullFileDir));

            new Thread(new ProcessStreamReader(p.getInputStream())).start();
            new Thread(new ProcessStreamReader(p.getErrorStream())).start();

            try {
                p.waitFor();
            }
            catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        catch (IOException e) {
            e.printStackTrace();
        }
        localFile.delete();

        addTestsFromTempDir(fullFileDir);

        return null;
    }

    private void addTestsFromTempDir(String dir) {
        int oldCount = TestcaseFactory.getTestCountForProblem(problem.getId(), Utils.getConnection(source), true);
        boolean startFromZero = true;
        if (!new File(dir + File.separatorChar + "input0.txt").exists()) {
            startFromZero = false;
        }
        int i = startFromZero ? 0 : 1;
        int testCount = 0;
        while (true) {
            File input = new File(dir + File.separatorChar + "input" + i + ".txt");
            File output = new File(dir + File.separatorChar + "output" + i + ".txt");
            if (input.exists() && output.exists()) {
                Testcase newTestcase = TestcaseFactory.getNewTestcase();
                newTestcase.setIndex(oldCount + testCount);
                newTestcase.setProblem(problem);
                newTestcase.setInput(Utils.getFileContentsTrimmed(input));
                newTestcase.setOutput(Utils.getFileContentsTrimmed(output));
                TestcaseFactory.updateTestcase(newTestcase, Utils.getConnection(source), true);
                testCount++;
            }
            else {
                break;
            }
            i++;
        }
    }
}
